package api

import (
	_ "github.com/mattn/go-sqlite3"
	"goexample.com/vulscaner/common"
	"goexample.com/vulscaner/database"
	"log"
	"log/slog"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func fscanInfoParser(taskID string) ([]string, map[string][]string, map[string][]string) {
	var fscanLogFileName string
	var ipList []string
	ipPort := make(map[string][]string)
	vulList := make(map[string][]string)

	// 未授权漏洞
	// vulList["Unauthenticated"] = []string{""}
	// POC已知漏洞
	// vulList["POC"] = []string{""}

	fscanLogFilePath := common.AbsolutPath() + "/log/fscan"
	sqls := "select fscan_logfile from task where id=" + taskID
	rows := database.GetRows(sqls)
	defer rows.Close()
	if rows.Next() {
		err := rows.Scan(&fscanLogFileName)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		return nil, nil, nil
	}

	fscanLogByte, err := os.ReadFile(fscanLogFilePath + "/" + fscanLogFileName)
	if err != nil {
		log.Fatal(err)
	}
	fscanLog := string(fscanLogByte)

	ipv4Reg := regexp.MustCompile(`((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}`)
	ipv4Hosts := ipv4Reg.FindAllString(fscanLog, -1)
	portReg := regexp.MustCompile(`((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(:\d?\d?\d?\d?\d)`)
	portHosts := portReg.FindAllString(fscanLog, -1)
	ipList = common.RemoveStringDuplicateNotCopy(ipv4Hosts)
	ports := common.RemoveStringDuplicateNotCopy(portHosts)
	for _, ip_port := range ports {
		ip := strings.Split(ip_port, ":")[0]
		port := strings.Split(ip_port, ":")[1]
		ipPort[ip] = append(ipPort[ip], port)
	}
	vulReg := regexp.MustCompile(`\[\+\].*`)
	vuls := vulReg.FindAllString(fscanLog, -1)
	for _, vul := range vuls {
		// Unauthenticated
		if strings.Contains(vul, "SSH") ||
			strings.Contains(vul, "mysql") ||
			strings.Contains(vul, "mssql") ||
			strings.Contains(vul, "ftp") {
			vulList["Unauthenticated"] = append(vulList["Unauthenticated"], vul[4:])
		} else if strings.Contains(vul, "InfoScan") {
			// 暂时忽略InfoScan
			continue
		} else {
			// vulList["POC"] = append(vulList["POC"], vul[4:])
			ipv4Addr := ipv4Reg.FindAllString(vul, -1)
			if ipv4Addr != nil {
				vulList[ipv4Addr[0]] = append(vulList[ipv4Addr[0]], vul[4:])
			}
		}
	}
	return ipList, ipPort, vulList
}

func VulXrayOutFileName(taskID string) ([]string, []string) {
	var xrayVulHtml []string
	var xrayOutFile []string
	var taskStartTime string
	sqls := "select task_start_time from task where id=" + taskID
	rows := database.GetRows(sqls)
	defer rows.Close()
	if rows.Next() {
		err := rows.Scan(&taskStartTime)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		return nil, nil
	}
	htmlPath := common.AbsolutPath() + "/log/xray/" + taskStartTime
	files, err := os.ReadDir(htmlPath)
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		fileName := file.Name()
		//变量已包含目录名
		if fileName[len(fileName)-4:len(fileName)] == "html" {
			xrayVulHtml = append(xrayVulHtml, taskStartTime+"/"+file.Name())
		} else {
			xrayOutFile = append(xrayOutFile, taskStartTime+"/"+file.Name())
		}
	}
	return xrayVulHtml, xrayOutFile
}

func DetectLiveHosts(taskID string) map[string][]string {
	var ipPort map[string][]string
	_, ipPort, _ = fscanInfoParser(taskID)
	return ipPort
}

func OriginScanLog(taskID string, logType string) []string {
	return nil
}

func DetectVulLists(taskID string) map[string][]string {
	var vulList map[string][]string
	_, _, vulList = fscanInfoParser(taskID)
	return vulList
}

func allEntry() []map[string]string {
	var entrys []map[string]string
	entrys = make([]map[string]string, 0)
	sqls := "select id,task_ipaddr,task_start_time from task"
	rows := database.GetRows(sqls)
	defer rows.Close()
	for {
		if rows.Next() {
			var taskid string
			var ip string
			var timeStamp string
			var singleEntry map[string]string
			singleEntry = make(map[string]string)
			err := rows.Scan(&taskid, &ip, &timeStamp)
			if err != nil {
				log.Fatal(err)
			}
			singleEntry["taskid"] = taskid
			singleEntry["ip"] = ip
			timestampInt, err := strconv.ParseInt(timeStamp, 10, 64)
			if err != nil {
				slog.Error(err.Error())
			}
			taskStartTime := time.Unix(timestampInt, 0)
			singleEntry["taskStartTime"] = taskStartTime.Format(time.RFC3339)
			entrys = append(entrys, singleEntry)
		} else {
			break
		}
	}
	return entrys
}
